﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Common;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.TeamFoundation.Framework.Server;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Server;
using System.Diagnostics;
using System.Xml.Linq;
using System.Xml;
using System.DirectoryServices;
using System.Net.Mail;
using System.Xml.Xsl;
using System.Configuration;
using System.Reflection;

namespace MailAlert
{
    public class WorkItemChangedEventHandler : ISubscriber
    {
        static string serverPath = "";
        static string ExternalURL = "";
        static string MailAddressFrom = "";
        static string SMTPHost = "";
        static string Password = "";
        static int Port = 0;
                
        static string projectCollectionFolder;
        static Uri projectCollectionUri;
    
        static WorkItemStore wiStore;
        static WorkItem wItem;
        static WorkItemChangedEvent workItemChangedEvent;
        static string teamProjectPath = "";

        static VersionControlServer versionControlServer;
        static TfsTeamProjectCollection projectCollection;

        static Dictionary<IdentityDescriptor, TeamFoundationIdentity> m_identities = new Dictionary<IdentityDescriptor, TeamFoundationIdentity>(IdentityDescriptorComparer.Instance);            

        public Type[] SubscribedTypes()
        {
            return new Type[1] { typeof(WorkItemChangedEvent) };
        }

        public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType,
            object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties)
        {
            

            statusCode = 0;
            properties = null;
            statusMessage = String.Empty;
            GetTfsServerName();
           
           projectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(TfsTeamProjectCollection.GetFullyQualifiedUriForName(serverPath));

            try
            {
                if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent)
                {
                    workItemChangedEvent = notificationEventArgs as WorkItemChangedEvent;
                    EventLog.WriteEntry("WorkItemChangedEventHandler", "WorkItem " + workItemChangedEvent.WorkItemTitle + " was modified");
                    EventLog.WriteEntry("WorkItemChangedEventHandler", "serverPath - " + serverPath);
                    projectCollectionFolder = requestContext.ServiceHost.VirtualDirectory.ToString();
                    projectCollectionUri = new Uri(serverPath + projectCollectionFolder);
                    projectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(projectCollectionUri);
                    wiStore = projectCollection.GetService<WorkItemStore>();
                    versionControlServer = projectCollection.GetService<VersionControlServer>();

                    EventLog.WriteEntry("WorkItemChangedEventHandler", "Before process workitem");
                    ProcessWorkItem();
                    EventLog.WriteEntry("WorkItemChangedEventHandler", "After process workitem");
                }
            }
            catch (Exception ex)
            {
                EventLog.WriteEntry("WorkItemChangedEventHandler", ex.Message);
            }
            return EventNotificationStatus.ActionPermitted;
        }

        private static void GetTfsServerName()
        {
            try
            {
                string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase);
                
                XmlDocument XmlDoc = new XmlDocument();
                XmlDoc.Load(assemblyFolder + @"\Settings.xml");
                
                // Declare the xpath for finding objects inside the XML file
                XmlNodeList XmlDocNodes = XmlDoc.SelectNodes("/configuration/tfssettings");
                XmlNodeList XmlDocExt = XmlDoc.SelectNodes("/configuration/Externaltfssettings");

                // Define a new List, to store the objects we pull out of the XML
                serverPath = XmlDocNodes[0].InnerText;

                ExternalURL = XmlDocExt[0].InnerText;

               

                XmlNodeList XmlDocNodes2 = XmlDoc.SelectNodes("/configuration/appSettings");

                foreach (XmlNode mailNode in XmlDocNodes2)
                {
                    
                    foreach (XmlNode varElement in mailNode.ChildNodes)
                    {
                        switch (varElement.Attributes["key"].Value)
                        {
                            case "MailAddressFrom":
                                MailAddressFrom = varElement.Attributes["value"].Value;
                                break;
                            case "SMTPHost":
                                SMTPHost = varElement.Attributes["value"].Value;
                                break;
                            case "Password":
                                Password = varElement.Attributes["value"].Value;
                                break;
                            case "Port":
                                Port = Convert.ToInt32(varElement.Attributes["value"].Value);
                                break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                EventLog.WriteEntry("WorkItemChangedEventHandler", ex.Message);
            }

       

        }

        public string Name
        {
            get { return "WorkItemChangedEventHandler"; }
        }

        public SubscriberPriority Priority
        {
            get { return SubscriberPriority.Normal; }
        }

        private static void ProcessWorkItem()
        {
            var teamProjects = versionControlServer.GetAllTeamProjects(false);

            for (int i = 0; i < teamProjects.Length; i++)
            {
                string teamProjectName = teamProjects[i].Name;
                var teamProject = teamProjects[i];
                Project teamProjectWI = wiStore.Projects[i];
                
                teamProjectPath = projectCollectionUri + teamProject.Name;

             

                if (workItemChangedEvent.PortfolioProject == teamProjectName)
                {
                    wItem = wiStore.GetWorkItem(workItemChangedEvent.CoreFields.IntegerFields[0].NewValue);

                    string CollGuid = projectCollection.InstanceId.ToString();
                    string AssignedTo = wItem.Fields["Assigned to"].Value.ToString();
                    string WorkItemId = wItem.Id.ToString();
                    string mail = GetEmailAddress(AssignedTo);
                                    
                   
                    SendMail(CollGuid, WorkItemId, mail);
                }
            }
        }

        private static string GetEmailAddress(string userDisplayName)
        {
            DirectorySearcher ds = new DirectorySearcher();
            ds.PropertiesToLoad.Add("mail");
            ds.Filter = String.Format("(&(displayName={0})(objectCategory=person)((objectClass=user)))", userDisplayName);

            SearchResultCollection results = ds.FindAll();
            if (results.Count == 0)
            {
                return string.Empty;
            }

            ResultPropertyValueCollection values = results[0].Properties["mail"];
            if (values.Count == 0)
            {
                return string.Empty;
            }

            return values[0].ToString();
        }

        
        private static void SendMail(string collID,string workItemId,string tomailAddrees)
        {
           
            MailMessage objeto_mail = new MailMessage();
            SmtpClient client = new SmtpClient();
            client.Port = Port;
            client.Host = SMTPHost;
            client.Timeout = 200000;
            client.DeliveryMethod = SmtpDeliveryMethod.Network;
            client.UseDefaultCredentials = true;
            client.EnableSsl = true;
            client.Credentials = new System.Net.NetworkCredential(MailAddressFrom, Password);
            objeto_mail.From = new MailAddress(MailAddressFrom);
            objeto_mail.To.Add(new MailAddress(tomailAddrees));
            //objeto_mail.CC.Add(new MailAddress("nagarajb@hotmail.com"));
            objeto_mail.Subject = "Work Item Changed:"+workItemId;
            string mailbody = serverPath+"/tfs/web/wi.aspx?pcguid=" + collID + "&id=" + workItemId;

            
            string mailbody2 = "";
            if (ExternalURL.Length > 0)
            {
                 mailbody2 = ExternalURL + "/tfs/web/wi.aspx?pcguid=" + collID + "&id=" + workItemId;
            }

            string tables = "<table border=1><tr><td>Work Item ID</td><td>" + wItem.Id.ToString() + "</td></tr><tr><td>Title</td><td>" + wItem.Title + "</td></tr><tr><td>State</td><td>" + wItem.State + "</td></tr><tr><td>Assigned To</td><td>" + wItem.Fields["Assigned to"].Value.ToString() + "</td></tr><tr><td>Internal URL</td><td>" + mailbody + "</td></tr><tr><td>External URL</td><td>" + mailbody2 + "</td></tr></table>";
      

            objeto_mail.IsBodyHtml = true;
            objeto_mail.Body = "<i>Hi " + wItem.Fields["Assigned to"].Value.ToString() + ","+"</i></br></br></br>" + tables + " </br></br>   Best regards; </br></br>Nagaraj</br></br></br>";
          
            client.Send(objeto_mail);
            EventLog.WriteEntry("WorkItemChangedEventHandler", "Email Sent");

        }

    }
}